import argparse
import struct
from elftools.elf.elffile import ELFFile

if __name__ == "__main__":
    #获取参数
    parser = argparse.ArgumentParser(description = 'Elf file output bcos executable binary file.')
    parser.add_argument('-i', help='Elf file path')
    parser.add_argument('-o', help='Bcos executable binary file.')

    args = parser.parse_args()

    # 参数赋值
    elf_name = args.i
    save_name = args.o

    # 打开文件    
    with open(elf_name, 'rb') as f:
        # 获取elf对象
        elffile = ELFFile(f)

        # 获取APP运行地址的offset
        mem_offset = 0
        for i in range(elffile.header.get('e_shnum')):
            section_header = elffile._get_section_header(i)
            if section_header.get('sh_type') == 'SHT_PROGBITS' and section_header.get('sh_flags') == 0b110:
                mem_offset = section_header.get('sh_size')

        # 获取APP段数据    
        data = None
        data_len = None
        mem_size = None
        for segment in elffile.iter_segments():
            data_len = len(segment.data())
            data = segment.data()
            # 获取memary的大小，其中包括code和全局变量
            mem_size = segment.header.get('p_memsz')

        # 将运行APP的必要数据按固定格式保存到二进制文件中
        # 保存格式：
        # file head: 8bytes
        # mem_offset:4bytes
        # data_size: 4bytes
        # segment_data: data_size bytes
        save_data = [
            ord('b'), ord('c'), ord('o'), ord('s'), ord(' '), ord('e'), ord('x'), ord('e'),
            mem_offset & 0xFF, (mem_offset >> 8)&0xFF, (mem_offset >> 16)&0xFF, (mem_offset >> 24)&0xFF,
            mem_size & 0xFF, (mem_size >> 8) & 0xFF, (mem_size >> 16) & 0xFF, (mem_size >> 24) & 0xFF
        ]
        
        zero = [0 for _ in range(mem_size - data_len)]
        save_data.extend(data)
        save_data.extend(zero)

        # 保存数据
        with open(save_name, 'wb') as fp:
            for i in save_data:
                a = struct.pack('B', i)
                fp.write(a)
            fp.close()
    
        # 关闭ELF文件
        f.close()

        # 输出可执行文件的信息
        print('code:', mem_offset)
        print('R/W:', mem_size - mem_offset)
        print('total:', mem_size)
